import json
import asyncio
from typing import Dict, List
from fastapi import WebSocket
from message_types import *
from game_room import GameRoom


class WebSocketHandler:
    def __init__(self, game_room: GameRoom):
        self.game_room = game_room
        self.connections: Dict[str, WebSocket] = {}  # player_id -> websocket
        self.websocket_to_player: Dict[WebSocket, str] = {}  # websocket -> player_id

        # 设置回调
        self.game_room.set_websocket_handler(self)

    async def add_connection(self, websocket: WebSocket):
        """添加WebSocket连接"""
        print(f"新的WebSocket连接: {websocket.client}")

    async def remove_connection(self, websocket: WebSocket):
        """移除WebSocket连接"""
        if websocket in self.websocket_to_player:
            player_id = self.websocket_to_player[websocket]
            print(f"玩家 {player_id} 断开连接")

            # 从游戏房间移除玩家
            await self.game_room.remove_player(player_id)

            # 清理连接映射
            del self.connections[player_id]
            del self.websocket_to_player[websocket]

            # 广播玩家离开消息
            await self.broadcast_message(ServerMessageType.PLAYER_LEFT.value, {
                "player_id": player_id
            }, exclude_websocket=websocket)

    async def handle_message(self, websocket: WebSocket, data: dict):
        """处理WebSocket消息"""
        try:
            message_type = data.get("type")
            message_data = data.get("data", {})

            print(f"收到消息: {message_type} from {websocket.client}")

            if message_type == ClientMessageType.JOIN_ROOM.value:
                await self.handle_join_room(websocket, message_data)
            elif message_type == ClientMessageType.PLAYER_ACTION.value:
                await self.handle_player_action(websocket, message_data)
            elif message_type == ClientMessageType.START_GAME.value:
                await self.handle_start_game(websocket, message_data)
            elif message_type == ClientMessageType.LEAVE_ROOM.value:
                await self.handle_leave_room(websocket, message_data)
            else:
                await self.send_error(websocket, f"未知消息类型: {message_type}")

        except Exception as e:
            print(f"处理消息错误: {e}")
            await self.send_error(websocket, f"处理消息失败: {str(e)}")

    async def handle_join_room(self, websocket: WebSocket, data: dict):
        """处理加入房间请求"""
        try:
            join_data = JoinRoomData(**data)

            # 检查玩家名是否已存在
            if join_data.player_name in self.connections:
                await self.send_error(websocket, "玩家名已存在")
                return

            # 添加玩家到游戏房间
            success, message = await self.game_room.add_player(
                join_data.player_name,
                join_data.total_players,
                join_data.ai_players
            )

            if not success:
                await self.send_error(websocket, message)
                return

            # 建立连接映射
            self.connections[join_data.player_name] = websocket
            self.websocket_to_player[websocket] = join_data.player_name

            print(f"玩家 {join_data.player_name} 加入房间")

            # 发送加入成功消息给当前玩家
            await self.send_message(websocket, ServerMessageType.PLAYER_JOINED.value, {
                "player_name": join_data.player_name,
                "message": "成功加入房间"
            })

            # 广播房间状态给所有玩家
            await self.broadcast_room_state()

        except Exception as e:
            await self.send_error(websocket, f"加入房间失败: {str(e)}")

    async def handle_player_action(self, websocket: WebSocket, data: dict):
        """处理玩家行动"""
        if websocket not in self.websocket_to_player:
            await self.send_error(websocket, "玩家未加入房间")
            return

        try:
            player_id = self.websocket_to_player[websocket]
            action_data = PlayerActionData(**data)

            print(f"玩家 {player_id} 行动: {action_data.action.value}")

            # 转发给游戏房间处理
            success, message = await self.game_room.handle_player_action(
                player_id, action_data.action, action_data.amount
            )

            if not success:
                await self.send_error(websocket, message)
                return

            # 广播游戏状态更新
            await self.broadcast_game_state()

        except Exception as e:
            await self.send_error(websocket, f"处理行动失败: {str(e)}")

    async def handle_start_game(self, websocket: WebSocket, data: dict):
        """处理开始游戏请求"""
        if websocket not in self.websocket_to_player:
            await self.send_error(websocket, "玩家未加入房间")
            return

        try:
            success, message = await self.game_room.start_game()

            if not success:
                await self.send_error(websocket, message)
                return

            print("游戏开始")

            # 广播游戏开始消息
            await self.broadcast_message(ServerMessageType.GAME_STARTED.value, {
                "message": "游戏开始！"
            })

            # 广播初始游戏状态
            await self.broadcast_game_state()

        except Exception as e:
            await self.send_error(websocket, f"开始游戏失败: {str(e)}")

    async def handle_leave_room(self, websocket: WebSocket, data: dict):
        """处理离开房间请求"""
        await self.remove_connection(websocket)

    async def send_message(self, websocket: WebSocket, message_type: str, data: dict):
        """发送消息给指定WebSocket"""
        try:
            message = {
                "type": message_type,
                "data": data
            }
            await websocket.send_text(json.dumps(message, ensure_ascii=False))
        except Exception as e:
            print(f"发送消息失败: {e}")

    async def send_error(self, websocket: WebSocket, error_message: str):
        """发送错误消息"""
        await self.send_message(websocket, ServerMessageType.ERROR.value, {
            "message": error_message
        })

    async def broadcast_message(self, message_type: str, data: dict, exclude_websocket: WebSocket = None):
        """广播消息给所有连接的WebSocket"""
        message = {
            "type": message_type,
            "data": data
        }

        disconnected_websockets = []

        for websocket in self.websocket_to_player.keys():
            if websocket == exclude_websocket:
                continue

            try:
                await websocket.send_text(json.dumps(message, ensure_ascii=False))
            except Exception as e:
                print(f"广播消息失败: {e}")
                disconnected_websockets.append(websocket)

        # 清理断开的连接
        for ws in disconnected_websockets:
            await self.remove_connection(ws)

    async def broadcast_room_state(self):
        """广播房间状态"""
        room_state_data = await self.game_room.get_room_state()
        await self.broadcast_message(ServerMessageType.ROOM_STATE.value, room_state_data)

    async def broadcast_game_state(self):
        """广播游戏状态"""
        # 给每个玩家发送个人化的游戏状态
        for player_id, websocket in self.connections.items():
            try:
                game_state_data = await self.game_room.get_game_state(player_id)
                await self.send_message(websocket, ServerMessageType.GAME_STATE.value, game_state_data)
            except Exception as e:
                print(f"发送游戏状态失败 {player_id}: {e}")

    async def send_action_request(self, player_id: str, action_data: dict):
        """向指定玩家发送行动请求"""
        if player_id in self.connections:
            websocket = self.connections[player_id]
            await self.send_message(websocket, ServerMessageType.ACTION_REQUIRED.value, action_data)
        else:
            print(f"玩家 {player_id} 的WebSocket连接不存在")

    def get_connected_players(self) -> List[str]:
        """获取所有连接的玩家ID"""
        return list(self.connections.keys())